home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 201-220 / scopedisk215 / update / update.asm < prev    next >
Assembly Source File  |  1995-03-19  |  61KB  |  1,338 lines

  1. *****************************************************************
  2. *                                                               *
  3. *    Program Name: Update                                       *
  4. *         Version: 1.0                                          *
  5. *  Change History: 11-Nov-87 Initial Program Version            *
  6. *                                                               *
  7. *   Copyright (c) 1987 - Bob Rakosky                            *
  8. *                                                               *
  9. *   USAGE:                                                      *
  10. *    Update [FROM] obj1 [obj2 ... obj12] TO dir [SINCE mfile]   *
  11. *                                                               *
  12. *    where obj1 ... obj12 are either files or directories,      *
  13. *               (with or without wildcards)                     *
  14. *          dir is the output directory name                     *
  15. *          mfile is a file name                                 *
  16. *                                                               *
  17. *  Will copy all files specified (or in directories specified)  *
  18. *  to dir IF the file's datestamp is later than the datestamp   *
  19. *  for file mfile (if specified) or later than the datestamp    *
  20. *  of the corresponding-named file in dir2 (if mfile not        *
  21. *  specified).  In the latter case, if the corresponding file   *
  22. *  does not exist in the output directory, the file is copied.  *
  23. *                                                               *
  24. *   NOTES                                                       *
  25. *       This program REQUIRES the use of ARP.library, which     *
  26. *       must be in your libs: logical directory.  If the        *
  27. *       library is not present, the program will issue an error *
  28. *       message and exit.                                       *
  29. *                                                               *
  30. *****************************************************************
  31.         include "exec/types.i"
  32.         include "exec/memory.i"
  33.         include "libraries/dos.i"
  34.         include "libraries/dosextens.i"
  35.         include "arpbase.i"
  36. *---------------------------------------------------------------*
  37. *                   Some commonly used macros                   *
  38. *---------------------------------------------------------------*
  39.  
  40. XTERN   MACRO           ;XTERN <reference> 
  41.         XREF    _LVO\1  ; Adds the '_LVO' prefix to it.
  42.         ENDM
  43.  
  44. CALL    MACRO           ;call < routine(register) >
  45.         jsr     _LVO\1  ; Adds the '_LVO' prefix to the routine name.
  46.         ENDM
  47.  
  48. *---------------------------------------------------------------*
  49. *                             Equates                           *
  50. *---------------------------------------------------------------*
  51. Absbase EQU     4
  52.  
  53. *---------------------------------------------------------------*
  54. *                       External references                     *
  55. *---------------------------------------------------------------*
  56.         XTERN   OpenLibrary
  57.         XTERN   CloseLibrary
  58.         XTERN   AllocMem
  59.         XTERN   FreeMem
  60.         XTERN   Output
  61.         XTERN   Write
  62.         XTERN   Read
  63.         XTERN   Lock
  64.         XTERN   UnLock
  65.         XTERN   ParentDir
  66.         XTERN   Examine
  67.         XTERN   ExNext
  68.         XTERN   Open
  69.         XTERN   Close
  70.         XTERN   IoErr
  71.         XTERN   DeviceProc
  72.  
  73. *---------------------------------------------------------------*
  74. *       Buffer Size for Read/Write Buffer                       *
  75. *---------------------------------------------------------------*
  76. RW_BUFS EQU     $4000           ;16 K Buffer size
  77.  
  78. *****************************************************************
  79. *                          Main Program                         *
  80. *****************************************************************
  81.  
  82. start   movem.l d1-d7/a0-a6,-(a7) ;save entry regs
  83.  
  84.         bsr     init            ;perform initialization
  85.         tst.l   d0              ;Q. Good Return?
  86.         bne     exit            ;A.  no - quit now
  87.  
  88.         bsr     parse           ;Parse the command line
  89.         tst.l   d0              ;Q. Good return?
  90.         bne     exit            ;A. No - exit
  91.  
  92.         tst.l   sinfil(a5)      ;Q. SINCE file name specified?
  93.         beq.s   main010         ;A. no since file - bypass
  94.         move.l  sinfil(a5),a0   ;address of SINCE file name
  95.         bsr     getfib          ;get datestamp of file
  96.         tst.l   d0              ;Q.  Good Return?
  97.         beq.s   main010         ;A.  Yes - continue
  98. *---------------------------------------------------------------*
  99. *         Unable to locate/examine 'SINCE' file                 *
  100. *---------------------------------------------------------------*
  101.         lea     nosinm(pc),a0
  102.         move.l  a0,d2           ;address message
  103.         move.l  #nosinml,d3
  104.         move.l  stdout(a5),d1
  105.         move.l  dosaddr(a5),a6
  106. *   Write(file,data,length)
  107. *          d1   d2    d3
  108.         CALL    Write(a6)
  109.         moveq.l #20,d0          ;set bad return code
  110.         bra     exit            ;and quit
  111.  
  112. main010:
  113.         lea     fib(a5),a1      ;point to fib
  114.         lea     fib_DateStamp(a1),a0  ;point to Datestamp
  115.         lea     cmpdate(a5),a1  ;save 'since date' here
  116. *---------------------------------------------------------------*
  117. *       The datestamp for comparison will be one tick less      *
  118. *       than that of the 'SINCE' file.                          *
  119. *---------------------------------------------------------------*
  120.         move.l  (a0)+,(a1)+     ;move datestamp days to compare area
  121.         move.l  (a0)+,(a1)+     ;move datestamp minutes to compare area
  122.         move.l  (a0),d0         ;get ticks
  123.         subq.l  #1,d0           ;decrement by 1
  124.         move.l  d0,(a1)         ;move ticks to compare area
  125.  
  126. *---------------------------------------------------------------*
  127. *       Verify Output specified is a directory                  *
  128. *---------------------------------------------------------------*
  129.         move.l  todir(a5),a0    ;address of output directory name
  130.         bsr     getfib          ;get file info
  131.         tst.l   d0              ;Q.  Good Return?
  132.         beq.s   main020         ;A.  Yes - continue
  133.         move.l  stdout(a5),d1   ;msg file
  134.         lea     noout(pc),a0
  135.         move.l  a0,d2           ;address message
  136.         move.l  #nooutl,d3      ;length of it.
  137.         move.l  a4,a6           ;DOSBase into a6
  138. *   Write(file,data,length)
  139. *          d1   d2    d3
  140.         CALL    Write(a6)       ;Send message to standard out
  141.         moveq.l #20,d0          ;set return code
  142.         bra.s   exit            ;and quit
  143.  
  144. main020:
  145.         lea     fib(a5),a0      ;point to file info block
  146.         move.l  fib_DirEntryType(a0),d0  ;file or directory indicator
  147.         bpl.s   main030         ;> 0 ==> directory - continue
  148. *---------------------------------------------------------------*
  149. *       TO specified is not a directory                         *
  150. *---------------------------------------------------------------*
  151.         move.l  stdout(a5),d1   ;msg file
  152.         lea     notdir(pc),a0
  153.         move.l  a0,d2           ;address message
  154.         move.l  #notdirl,d3     ;length of it.
  155.         move.l  a4,a6           ;DOSBase into a6
  156. *   Write(file,data,length)
  157. *          d1   d2    d3
  158.         CALL    Write(a6)       ;Send message to standard out
  159.         moveq.l #20,d0          ;set return code
  160.         bra.s   exit            ;and quit
  161.  
  162. main030:
  163. *---------------------------------------------------------------*
  164. *       copy target directory name to buffer and mark end       *
  165. *---------------------------------------------------------------*
  166.         move.l  todir(a5),a0    ;path name
  167.         lea     outbuf(a5),a1   ;buffer area
  168. 1$:     move.b  (a0)+,(a1)+     ;next char
  169.         bne     1$              ;loop until end of string 
  170.         lea     -2(a1),a1       ;back up to last non-blank character
  171.         move.b  (a1)+,d0        ;examine last character
  172.         cmp.b   #':',d0         ;Q. Last character colon ?
  173.         beq.s   2$              ;A. yes - don't append slash
  174.         move.b  #'/',(a1)+      ;A. no - append a slash
  175. 2$:
  176.         move.l  a1,outfnam(a5)  ;concat output file name here
  177.  
  178. *---------------------------------------------------------------*
  179. *   loop and process all arguments                              *
  180. *---------------------------------------------------------------*
  181.         move.w  argc(a5),d7     ;number of arguments
  182.         ext.l   d7
  183.         move.l  #2,d6           ;reduce by at least 1 (for target)
  184.                                 ;  plus 1 to make relative to 0
  185.         tst.l   sinfil(a5)      ;Q. Was 'since' option specified?
  186.         beq.s   main040         ;A. No - bypass adjustment
  187.         addq.l  #1,d6           ;A. Yes - one less input arguments
  188. main040:
  189.         sub.l   d6,d7           ;adjust loop counter
  190.         clr.l   d6              ;index value into d6
  191.         lea     argv(a5),a4     ;point to first arg
  192. main050:
  193.         move.l  0(a4,d6.w),a0   ;pick up next argument
  194.         bsr     procarg         ;process input argument
  195.         tst.l   d0              ;Q.  Good return?
  196.         bne.s   exit            ;A.  No - quit now
  197.         addq.w  #4,d6           ;increment index
  198.         dbra    d7,main050      ;loop on
  199. *---------------------------------------------------------------*
  200. *   End of processing loop - set good return code and exit      *
  201. *---------------------------------------------------------------*
  202.         clr.l   d0              ;set good return code and exit
  203. exit:   move.l  d0,-(a7)        ;save return code
  204.         bsr     cleanup         ;free resources
  205.         move.l  (a7)+,d0        ;restore return code
  206.         movem.l (a7)+,d1-d7/a0-a6 ;restore other regs
  207.         rts                     ;return to caller
  208.  
  209.         PAGE
  210. *****************************************************************
  211. *     Section Name: init                                        *
  212. *         Function: Performs initial housekeeping               *
  213. *  Entry Registers: a0 - command line string                    *
  214. *                   d0 - command line length                    *
  215. *   Exit Registers: d0 - return code (0 = success)              *
  216. *                   a5 - work area address                      *
  217. *****************************************************************
  218.  
  219. init:
  220.         move.l  a0,a3           ;save command line
  221.         move.l  d0,d3           ;  address and length
  222. *---------------------------------------------------------------*
  223. *                       Open DOS Library                        *
  224. *---------------------------------------------------------------*
  225.         move.l  Absbase,a6      ;find library
  226.         lea     dosname(pc),a1  ;point to libname string
  227.         moveq   #33,d0          ;version at least 1.2 (or higher)
  228. *  libbase = OpenLibrary(libname,version);
  229. *    d0                    a1      d0
  230.         CALL    OpenLibrary(a6) ;open dos library
  231.         movea.l d0,a4           ;save dos pointer for later use
  232.         beq     init_err        ;OpenLibrary failed, can't tell user - just exit
  233.  
  234. *---------------------------------------------------------------*
  235. *               Get Std Output File Handle                      *
  236. *---------------------------------------------------------------*
  237.         movea.l a4,a6           ;DosBase into a6
  238. *   stdout = Output();
  239. *     d0
  240.         CALL    Output(a6)      ;get file handle for screen
  241.         move.l  d0,d4           ;save filehandle
  242.  
  243. *---------------------------------------------------------------*
  244. *                       Allocate work area                      *
  245. *---------------------------------------------------------------*
  246.         move.l  #wk_lgth,d0     ;length in d0
  247.         move.l  #MEMF_CLEAR,d1  ;type in d1
  248.         move.l  Absbase,a6
  249. *   area = AllocMem(size,flags);
  250. *    d0              d1   d0
  251.         CALL    AllocMem(a6)    ;call AllocMem
  252.  
  253.         movea.l d0,a5           ;address work area 
  254.         bne.s   init010        ;we now have a work area
  255.  
  256. *---------------------------------------------------------------*
  257. *               Allocate failed - tell user and exit            *
  258. *---------------------------------------------------------------*
  259.         move.l  d4,d1           ;Std Output file handle
  260.         beq.s   init_err        ;couldn't get screen handle - just exit
  261.  
  262.         lea     nomem(pc),a0
  263.         move.l  a0,d2           ;address message
  264.         move.l  #nomeml,d3      ;length of it.
  265.         move.l  a4,a6           ;DOSBase into a6
  266. *   Write(file,data,length)
  267. *          d1   d2    d3
  268.         CALL    Write(a6)       ;Send message to standard out
  269.         bra.s   init_err        ;and leave
  270.  
  271. *---------------------------------------------------------------*
  272. *               We now have a work area                         *
  273. *---------------------------------------------------------------*
  274. init010:
  275.         move.l  a4,dosaddr(a5)  ;save dos address
  276.         move.l  a3,cmdline(a5)  ;address of command line
  277.         move.l  d3,cmdlen(a5)   ;length of command line
  278.         move.l  d4,stdout(a5)   ;save address of Std Output
  279.  
  280. *---------------------------------------------------------------*
  281. *               Open ARP Library                                *
  282. *---------------------------------------------------------------*
  283.         move.l  Absbase,a6      ;find library
  284.         lea     arpname(pc),a1  ;point to libname string
  285.         moveq   #ArpVersion,d0          ;version at least 1.2 (or higher)
  286. *  libbase = OpenLibrary(libname,version);
  287. *     d0                   a1       d0
  288.         CALL    OpenLibrary(a6) ;open dos library
  289.         move.l  d0,arpbase(a5)  ;save base pointer for later use
  290.         bne     init020         ;OpenLibrary OK - initialization complete
  291. *---------------------------------------------------------------*
  292. *               Unable to open Arp Library                      *
  293. *---------------------------------------------------------------*
  294.         move.l  stdout(a5),d1   ;msg file
  295.         lea     noarp(pc),a0
  296.         move.l  a0,d2           ;address message
  297.         move.l  #noarpl,d3      ;length of it.
  298.         move.l  a4,a6           ;DOSBase into a6
  299. *   Write(file,data,length);
  300. *          d1   d2    d3
  301.         CALL    Write(a6)       ;Send message to standard out
  302.         bra.s   init_err        ;and leave
  303.  
  304. *---------------------------------------------------------------*
  305. *               Initialization Complete                         *
  306. *---------------------------------------------------------------*
  307. init020:
  308.         clr.l   d0              ;set good return code
  309.         rts                     ;  return to sender
  310.  
  311. *---------------------------------------------------------------*
  312. *               Initialization Error                            *
  313. *---------------------------------------------------------------*
  314. init_err:
  315.         moveq.l #20,d0          ;set error return code
  316.         rts
  317.  
  318.         PAGE
  319. *****************************************************************
  320. *     Section Name: parse                                       *
  321. *         Function: Parse the command line                      *
  322. *       Entry Data: cmdline - address of command line           *
  323. *                   cmdlen - length of command line             *
  324. *                         NOTE - relative to ZERO               *
  325. *        Exit Data: d0 - return code (0 = success, 20 = error)  *
  326. *                   argc - number of parameters specified       *
  327. *                   argv - a table of pointers to the 'words'   *
  328. *                                                               *
  329. *****************************************************************
  330.  
  331. parse:
  332.         movea.l cmdline(a5),a0  ;point to command line
  333.         move.l  cmdlen(a5),d0   ;length of command line
  334.         lea     cmdpr(pc),a1    ;help string
  335.         lea     argv(a5),a2     ;arg array
  336.         lea     templ(pc),a3    ;command template
  337.         move.l  arpbase(a5),a6  ;arpbase
  338. *  argc = GADS(cmdline,cmdlength,help,&argv[0],template);
  339. *   d0           a0       d0      a1    a2        a3
  340.         CALL    GADS(a6)        ;parse the command line
  341.         move.w  d0,argc(a5)     ;store arg count
  342.         ble.s   pars_err        ;==-1 -> parse error
  343.                                 ;==0 parsed ok but no arguments
  344.  
  345. *---------------------------------------------------------------*
  346. *               Successful parse of command line                *
  347. *---------------------------------------------------------------*
  348.         clr.l   d0              ;good return code
  349.         rts                     ;return
  350.  
  351. *---------------------------------------------------------------*
  352. *  Unexpected error in parsing routine - should never happen    *
  353. *---------------------------------------------------------------*
  354.  
  355. pars_err:
  356.         lea     ferrm(pc),a0
  357.         move.l  a0,d2           ;Set up and write err msg to console
  358.         move.l  #ferrml,d3
  359.         move.l  stdout(a5),d1
  360.         move.l  dosaddr(a5),a6
  361. *   Write(file,data,length);
  362. *          d1   d2    d3
  363.         CALL    Write(a6)
  364.         moveq.l #20,d0          ;set bad return code
  365.         rts                     ;and return
  366.  
  367.         PAGE
  368. *****************************************************************
  369. *     Section Name: cleanup                                     *
  370. *                                                               *
  371. *         Function: Frees all system resources acquired         *
  372. *                                                               *
  373. *       Entry Data: a5 - Address of global work area (if it     *
  374. *                        exists                                 *
  375. *                                                               *
  376. *        Exit Data: none                                        *
  377. *                                                               *
  378. *****************************************************************
  379.  
  380. cleanup:
  381.         move.l  a5,d0           ;address of work area
  382.         beq.s   cleanret        ;  none - nothing to clean up
  383.         move.l  databuf(a5),d0  ;Q. do we have a read/write buffer?
  384.         beq.s   cln010          ;A.  NO - bypass freeing it
  385.         move.l  d0,a1           ;address of area to free
  386.         move.l  #RW_BUFS,d0     ;size of area to free
  387.         move.l  Absbase,a6
  388. *  FreeMem(area,size);
  389. *           a1   d0
  390.         CALL    FreeMem(a6)
  391.  
  392. cln010:
  393.         move.l  arpbase(a5),d0  ;Q. Is ARP library open?
  394.         beq.s   cln020          ;A. no - don't close it
  395.         move.l  d0,a1           ;address of arp base
  396.         move.l  Absbase,a6
  397. *  CloseLibrary(libbase);
  398. *                 d0
  399.         CALL    CloseLibrary(a6)
  400.  
  401. cln020:
  402.         move.l  a5,a1           ;address of work area
  403.         move.l  #wk_lgth,d0     ;length of work area
  404.         move.l  Absbase,a6      ;exec library
  405. *  FreeMem(area,size);
  406. *           a1   d0
  407.         CALL    FreeMem(a6)     ;free work area
  408. cleanret:
  409.         rts                     ;return to caller
  410.  
  411.         PAGE
  412. *****************************************************************
  413. *     Section Name: procarg                                     *
  414. *                                                               *
  415. *         Function: Processes a single input argument from the  *
  416. *                   command-line                                *
  417. *                                                               *
  418. *       Entry Data: a0 - pointer to argument, which is either   *
  419. *                       a file or directory (with/without       *
  420. *                       wild-cards                              *
  421. *                                                               *
  422. *        Exit Data: d0 - return code (0 = success)              *
  423. *                                                               *
  424. *****************************************************************
  425.  
  426. procarg:
  427.         move.l  a0,-(a7)                ;push passed argument
  428.         move.l  #128,d0
  429.         lea     anchor(a5),a0           ;point to f/n search anchor
  430.         move.l  d0,AP_LENGTH(a0)        ;length of fname
  431.         move.l  (a7)+,d0                ;pop passed argument
  432.         move.l  arpbase(a5),a6          ;ARP base
  433. *  rc = FindFirst(pattern,chain)
  434. *  d0               d0      a0
  435.         CALL    FindFirst(a6)
  436.         tst.l   d0                      ;Q.  Good Return?
  437.         bne.s   parg_err                ;A.  No - error exit
  438. parg010:
  439.         lea     anchor(a5),a1           ;point to search anchor
  440.         lea     AP_INFO(a1),a0          ;point to internal FIB
  441.         move.l  fib_DirEntryType(a0),d0  ;file or directory indicator
  442.         bpl     parg020                 ;> 0 ==> directory - continue
  443. *---------------------------------------------------------------*
  444. *       entry is a file                                         *
  445. *---------------------------------------------------------------*
  446.         lea     fname(a5),a1            ;point to full path name
  447.                                         ;note - a0 still points to fib
  448.         bsr     dofile                  ;process input file
  449.         tst.l   d0                      ;Q. Good return?
  450.         bne.s   parg_err                ;A. no - quit
  451.         bra.s   parg030                 ;continue with next in chain
  452.  
  453. parg020:
  454. *---------------------------------------------------------------*
  455. *       entry is a directory                                    *
  456. *---------------------------------------------------------------*
  457.         bsr     dodir                   ;process input directory
  458.         tst.l   d0                      ;Q. Good return?
  459.         bne.s   parg_err                ;A. no - quit
  460.  
  461. parg030:
  462.         lea     anchor(a5),a0           ;search anchor
  463.         move.l  arpbase(a5),a6
  464. *  rc = FindNext(chain)
  465. *  d0              a0
  466.         CALL    FindNext(a6)
  467.         tst.l   d0
  468.         beq.s   parg010                 ;loop on if next entry
  469.  
  470. *---------------------------------------------------------------*
  471. *       End of chain - we are done with this argument           *
  472. *---------------------------------------------------------------*
  473.         lea     anchor(a5),a0           ;point to anchor
  474.         move.l  arpbase(a5),a6          ;ARP base
  475. *  FreeAnchorChain(chain)
  476. *                    a0
  477.         CALL    FreeAnchorChain(a6)
  478.  
  479.         clr.l   d0                      ;return code
  480.         rts
  481.  
  482. parg_err:
  483.         moveq.l #20,d0                  ;set error return code
  484.         rts
  485.  
  486.         PAGE
  487. *****************************************************************
  488. *     Section Name: dodir                                       *
  489. *                                                               *
  490. *         Function: Processes a file directory included in the  *
  491. *                   input argument list                         *
  492. *                                                               *
  493. *       Entry Data: fname(a5) contains the full path of the     *
  494. *                       directory                               *
  495. *                                                               *
  496. *        Exit Data: d0 - return code (0 = success)              *
  497. *                                                               *
  498. *  NOTE:  This routine uses the AmigaDOS Examine/ExNext         *
  499. *       functions, since wild cards are not needed              *
  500. *                                                               *
  501. *****************************************************************
  502.  
  503. dodir:
  504.         movem.l d2-d3/a3-a4,-(a7)       ;save registers
  505.         lea     dirbuf(a5),a0   ;buffer area to build file names
  506.         lea     fname(a5),a1    ;path name of directory
  507. 1$:     move.b  (a1)+,(a0)+     ;move directory name to buffer
  508.         bne.s   1$              ;stop at null
  509.  
  510.         lea     -2(a0),a0       ;point at last character
  511.         move.b  (a0)+,d0        ;inspect last character
  512.         cmp.b   #':',d0         ;Q. Is last character ':'?
  513.         beq.s   ddir010         ;A. yes - don't append a /
  514.         move.b  #'/',(a0)+      ;   no - append a / for path name
  515. ddir010:
  516.         move.l  a0,a4           ;save beginning address for file name
  517. *---------------------------------------------------------------*
  518. *       Allocate memory for local FIB                           *
  519. *---------------------------------------------------------------*
  520.         move.l  #fib_SIZEOF,d0  ;size of fib
  521.         move.l  #MEMF_CLEAR,d1  ;allocation type
  522.         move.l  Absbase,a6      ;Exec base
  523. *  *ptr = AllocMem(size,type)
  524. *   d0              d0   d1
  525.         CALL    AllocMem(a6)    ;allocate fib
  526.         tst.l   d0              ;Q.  Allocation successful?
  527.         bne.s   ddir020         ;A.  yes - continue
  528. *---------------------------------------------------------------*
  529. *       Unable to allocate FIB - gotta quit                     *
  530. *---------------------------------------------------------------*
  531.         move.l  stdout(a5),d1           ;Std Output file handle
  532.         lea     nomem(pc),a0
  533.         move.l  a0,d2           ;address message
  534.         move.l  #nomeml,d3      ;length of it.
  535.         move.l  dosaddr(a5),a6          ;DOSBase into a6
  536. *   Write(file,data,length)
  537. *          d1   d2    d3
  538.         CALL    Write(a6)       ;Send message to standard out
  539.         bra     ddir_err        ;and leave
  540.  
  541. ddir020:
  542.         move.l  d0,a3           ;save pointer to FIB
  543. *---------------------------------------------------------------*
  544. *               Obtain a lock on directory                      *
  545. *---------------------------------------------------------------*
  546.         lea     fname(a5),a0    ;point to directory name
  547.         move.l  a0,d1
  548.         move.l  #ACCESS_READ,d2 ;get a shared lock
  549.         move.l  dosaddr(a5),a6
  550. *  Lock = Lock(name,accessMode)
  551. *   d0          d1      d2
  552.         CALL    Lock(a6)
  553.         tst.l   d0              ;Q.  Lock obtained?
  554.         bne.s   ddir030         ;A.  yes - continue
  555.  
  556.         lea     fname(a5),a0
  557.         move.l  a0,work(a5)     ;build argument list
  558.         lea     work(a5),a1     ;point to argument list
  559.         lea     dlokerr(pc),a0  ;printf pattern
  560.         move.l  arpbase(a5),a6
  561. *  Printf(string,*args)
  562. *           a0     a1
  563.         CALL    Printf(a6)
  564.         bra     ddir_err        ;and leave
  565.  
  566. ddir030:
  567.         move.l  d0,d3           ;save lock
  568. *---------------------------------------------------------------*
  569. *       Walk the directory chain, using Examine/ExNext          *
  570. *---------------------------------------------------------------*
  571.         move.l  d3,d1           ;lock
  572.         move.l  a3,d2           ;pointer to fib
  573.         move.l  dosaddr(a5),a6
  574. *  success = Examine(lock,fib)
  575. *     d0              d1   d2
  576.         CALL    Examine(a6)
  577.         tst.l   d0              ;Q. Successful?
  578.         bne.s   ddir040         ;A. yes - continue
  579.  
  580.         lea     fname(a5),a0
  581.         move.l  a0,work(a5)     ;build argument list
  582.         lea     work(a5),a1     ;point to argument list
  583.         lea     dexerr(pc),a0   ;printf pattern
  584.         move.l  arpbase(a5),a6
  585. *  Printf(string,*args)
  586. *           a0     a1
  587.         CALL    Printf(a6)
  588.         bra     ddir_err        ;and leave
  589.  
  590. ddir040:
  591. *---------------------------------------------------------------*
  592. *       If entry is for a directory skip it                     *
  593. * NOTE: The program will NOT recursively walk a nested          *
  594. *       directory structure                                     *
  595. *---------------------------------------------------------------*
  596.         move.l  fib_DirEntryType(a3),d0 ;file or directory indicator
  597.         bpl.s   ddir050         ; >= 0 ==> directory - bypass it
  598. *---------------------------------------------------------------*
  599. *       Entry is a file - build full file name                  *
  600. *---------------------------------------------------------------*
  601.         move.l  a4,a0           ;point to file path
  602.         lea     fib_FileName(a3),a1  ;point to file name
  603. 1$:     move.b  (a1)+,(a0)+     ;append file name to path
  604.         bne.s   1$              ;loop until null byte
  605.  
  606. *---------------------------------------------------------------*
  607. *       Now process the file                                    *
  608. *---------------------------------------------------------------*
  609.         move.l  a3,a0           ;point to FIB
  610.         lea     dirbuf(a5),a1   ;point to path name
  611.         bsr     dofile          ;process file
  612.         tst.l   d0              ;Q.  Success?
  613.         beq.s   ddir050         ;A.  yes - continue
  614. *---------------------------------------------------------------*
  615. *       Error - free local resources and exit                   *
  616. *---------------------------------------------------------------*
  617.         move.l  a3,a1           ;address of fib
  618.         move.l  #fib_SIZEOF,d0  ;length of fib
  619.         move.l  Absbase,a6      ;exec library
  620. *  FreeMem(area,size);
  621. *           a1   d0
  622.         CALL    FreeMem(a6)     ;free work area
  623.  
  624.         move.l  d3,d1           ;lock
  625.         move.l  dosaddr(a5),a6
  626. *  UnLock(lock)
  627. *          d1
  628.         CALL    UnLock(a6)      ;free lock
  629.         bra.s   ddir_err
  630.  
  631. ddir050:
  632. *---------------------------------------------------------------*
  633. *               Get next entry in directory                     *
  634. *---------------------------------------------------------------*
  635.         move.l  d3,d1           ;lock
  636.         move.l  a3,d2           ;pointer to FIB
  637.         move.l  dosaddr(a5),a6
  638. *  success = ExNext(lock,fib)
  639. *     d0             d1   d2
  640.         CALL    ExNext(a6)
  641.         tst.l   d0              ;Q.  Success?
  642.         bne.s   ddir040         ;A.  yes - loop on to process this entry
  643. *---------------------------------------------------------------*
  644. *       Insure that error is NO_MORE_ENTRIES                    *
  645. *---------------------------------------------------------------*
  646.         move.l  dosaddr(a5),a6
  647. *  error = IoErr()
  648. *   d0
  649.         CALL    IoErr(a6)       ;get DOS error code
  650.         move.l  d0,-(a7)        ;save error code on stack
  651. *---------------------------------------------------------------*
  652. *               Free Resources                                  *
  653. *---------------------------------------------------------------*
  654.         move.l  a3,a1           ;address of fib
  655.         move.l  #fib_SIZEOF,d0  ;length of fib
  656.         move.l  Absbase,a6      ;exec library
  657. *  FreeMem(area,size);
  658. *           a1   d0
  659.         CALL    FreeMem(a6)     ;free work area
  660.  
  661.         move.l  d3,d1           ;lock
  662.         move.l  dosaddr(a5),a6
  663. *  UnLock(lock)
  664. *          d1
  665.         CALL    UnLock(a6)      ;free lock
  666.  
  667.         move.l  (a7)+,d0        ;pop DOS error code
  668.         cmp.l   #ERROR_NO_MORE_ENTRIES,d0  ;Q.  Expected 'error' value?
  669.         beq.s   ddir060         ;yes - ok to return
  670.         move.l  d0,work(a5)     ;no - put error code in arg list
  671.         lea     work(a5),a1     ;point to arg list
  672.         lea     baddir(pc),a0   ;Printf pattern
  673.         move.l  arpbase(a5),a6
  674. *  Printf(string,*args)
  675. *           a0     a1
  676.         CALL    Printf(a6)      ;print error message
  677.         bra.s   ddir_err        ;take error exit
  678.  
  679. ddir060:
  680.         movem.l (a7)+,d2-d3/a3-a4       ;restore registers
  681.         clr.l   d0              ;good return code
  682.         rts
  683.  
  684. ddir_err:
  685.         movem.l (a7)+,d2-d3/a3-a4       ;restore registers
  686.         moveq.l #20,d0          ;error return code
  687.         rts
  688.  
  689.         PAGE
  690. *****************************************************************
  691. *     Section Name: dofile                                      *
  692. *                                                               *
  693. *         Function: Processes a file included in the input      *
  694. *                   argument list                               *
  695. *                                                               *
  696. *       Entry Data: a0 - FIB for file                           *
  697. *                   a1 - full path name for file                *
  698. *                                                               *
  699. *        Exit Data: d0 - return code (0 = success)              *
  700. *                                                               *
  701. *****************************************************************
  702.  
  703. dofile:
  704.         movem.l d2-d5/a2-a4,-(a7)       ;save registers
  705.         move.l  a0,a3           ;save FIB pointer
  706.         move.l  a1,a4           ;save name pointer
  707. *---------------------------------------------------------------*
  708. *       Construct full path name for output file                *
  709. *---------------------------------------------------------------*
  710.         lea     fib_FileName(a0),a1     ;point to file name of input
  711.         move.l  outfnam(a5),a0  ;point into buffer containing output path
  712. 1$:     move.b  (a1)+,(a0)+     ;append file name to path
  713.         bne.s   1$              ;loop until null-byte
  714.  
  715. *---------------------------------------------------------------*
  716. *               Get date for comparison                         *
  717. *---------------------------------------------------------------*
  718.         bsr     getcdate        ;get datestamp for compare
  719.         tst.l   d0              ;Q.  Good return?
  720.         bne     dofl_err        ;A.  No - quit now
  721.  
  722.         lea     cmpdate(a5),a0  ;point to compare date stamp
  723.         lea     fib_DateStamp(a3),a1 ;point to FIB date stamp
  724.         moveq.l #2,d0           ;loop count - 3 long words
  725. dofl010:
  726.         move.l  (a0)+,d1        ;next long word from compare date
  727.         cmp.l   (a1)+,d1        ;compare to next long word from FIB
  728.         blt.s   dofl020         ;branch if FIB datestamp is higher
  729.         bgt     dofl090         ;if FIB datestamp lower - do not process
  730.         dbra    d0,dofl010      ;check entire DateStamp
  731.         bra     dofl090         ;FIB date is equal to - skip file
  732.  
  733. dofl020:
  734. *---------------------------------------------------------------*
  735. *  File is to be processed - tell user                          *
  736. *---------------------------------------------------------------*
  737.         move.l  a4,work(a5)     ;build argument list
  738.         lea     work(a5),a1     ;point to argument list
  739.         lea     fline(pc),a0    ;printf pattern
  740.         move.l  arpbase(a5),a6
  741. *  Printf(string,*args)
  742. *           a0     a1
  743.         CALL    Printf(a6)
  744. *---------------------------------------------------------------*
  745. *       Open Input file                                         *
  746. *---------------------------------------------------------------*
  747.         move.l  a4,d1           ;pointer to file name
  748.         move.l  #MODE_OLDFILE,d2        ;access mode
  749.         move.l  dosaddr(a5),a6
  750. *  file = Open(name,accessMode)
  751. *   d0          d1      d2
  752.         CALL    Open(a6)        ;Open input file
  753.         tst.l   d0              ;Q. open successful?
  754.         bne.s   dofl030         ;A. yes - continue
  755. *---------------------------------------------------------------*
  756. *       Input file failed to open - inform user and exit        *
  757. *---------------------------------------------------------------*
  758.         lea     iopnerm(pc),a0
  759.         move.l  a0,d2           ;Set up and write err msg to console
  760.         move.l  #iopnerl,d3
  761.         move.l  stdout(a5),d1
  762.         move.l  dosaddr(a5),a6
  763. *   Write(file,data,size)
  764. *          d1   d2   d3
  765.         CALL    Write(a6)
  766.         bra     dofl_err
  767.  
  768. dofl030:
  769.         move.l  d0,d4           ;save input file handle
  770. *---------------------------------------------------------------*
  771. *               Open output file                                *
  772. *---------------------------------------------------------------*
  773.         lea     outbuf(a5),a0   ;point to output file path/name
  774.         move.l  a0,d1           ;pointer to file name
  775.         move.l  #MODE_NEWFILE,d2        ;access mode
  776.         move.l  dosaddr(a5),a6
  777. *  file = Open(name,accessMode)
  778. *   d0          d1      d2
  779.         CALL    Open(a6)        ;Open output file
  780.         tst.l   d0              ;Q. open successful?
  781.         bne.s   dofl040         ;A. yes - continue
  782. *---------------------------------------------------------------*
  783. *       Output file failed to open - inform user and exit       *
  784. *---------------------------------------------------------------*
  785.         lea     oopnerm(pc),a0
  786.         move.l  a0,d2           ;Set up and write err msg to console
  787.         move.l  #oopnerl,d3
  788.         move.l  stdout(a5),d1
  789.         move.l  dosaddr(a5),a6
  790. *   Write(file,data,size)
  791. *          d1   d2   d3
  792.         CALL    Write(a6)
  793.         move.l  d4,d1           ;Close Input file
  794.         move.l  dosaddr(a5),a6
  795. *   Close(file)
  796. *          d1
  797.         CALL    Close(a6)
  798.         bra.s   dofl_err
  799.  
  800. dofl040:
  801.         move.l  d0,d5           ;save output file handle
  802.         move.l  d4,d1           ;input file handle in d1
  803.         bsr     copyfile        ;copy the files
  804.         move.l  d0,-(a7)        ;save copy return code
  805.  
  806. *---------------------------------------------------------------*
  807. *       Close the files                                         *
  808. *---------------------------------------------------------------*
  809.         move.l  d5,d1           ;Output file handle
  810.         move.l  dosaddr(a5),a6
  811. *  Close(file)
  812. *         d1
  813.         CALL    Close(a6)       ;close output file
  814.         move.l  d4,d1           ;Input file handle
  815.         move.l  dosaddr(a5),a6
  816. *  Close(file)
  817. *         d1
  818.         CALL    Close(a6)       ;close input file
  819.  
  820.         move.l  (a7)+,d0        ;restore return code from copy
  821.         tst.l   d0              ;Q. Good return from copy?
  822.         bne.s   dofl_err        ;A. no - quit
  823. *---------------------------------------------------------------*
  824. *       Set DateStamp of output file to match input             *
  825. *---------------------------------------------------------------*
  826.         move.l  a3,a0           ;FIB of input file
  827.         bsr     setdate         ;call set date routine
  828.  
  829.         lea     foklin(pc),a0
  830.         move.l  a0,d2           ;Set up and write ok msg to console
  831.         move.l  #foklinl,d3
  832.         move.l  stdout(a5),d1
  833.         move.l  dosaddr(a5),a6
  834. *   Write(file,data,length)
  835. *          d1   d2    d3
  836.         CALL    Write(a6)
  837.  
  838. dofl090:
  839.         clr.l   d0
  840.         movem.l (a7)+,d2-d5/a2-a4       ;restore registers
  841.         rts
  842.  
  843. dofl_err:
  844.         moveq.l #20,d0                  ;set error return code
  845.         movem.l (a7)+,d2-d5/a2-a4       ;restore registers
  846.         rts
  847.  
  848.         PAGE
  849. *****************************************************************
  850. *     Section Name: getcdate                                    *
  851. *                                                               *
  852. *         Function: Obtains the datestamp of the corresponding  *
  853. *                   output file (if since option not used)      *
  854. *                                                               *
  855. *       Entry Data: outbuf(a5) contains full path name of       *
  856. *                       output file                             *
  857. *                                                               *
  858. *        Exit Data: cmpdate(a5) will contain the date for       *
  859. *                       comparison                              *
  860. *                   d0 - return code (0 = success)              *
  861. *                                                               *
  862. *       NOTE:   if 'since' option was specified, this routine   *
  863. *               will just return.  The cmpdate field has already*
  864. *               been populated with the correct date            *
  865. *                                                               *
  866. *****************************************************************
  867.  
  868. getcdate:
  869.         tst.l   sinfil(a5)      ;Q. SINCE file specified?
  870.         beq.s   gcdt010         ;A. No - proceed
  871.         clr.l   d0              ;A. yes - set good return code
  872.         rts                     ;       and return
  873. gcdt010:
  874.         movem.l d2-d4,-(a7)     ;save work registers
  875. *---------------------------------------------------------------*
  876. *  Obtain a lock on the output file - if file does not exist    *
  877. *  this will fail.  In this case, set cmpdate to zeros so the   *
  878. *  comparison will result in the file being processed           *
  879. *---------------------------------------------------------------*
  880.         lea     outbuf(a5),a0   ;point to output file path/name
  881.         move.l  a0,d1
  882.         move.l  #ACCESS_READ,d2 ;get a shared lock
  883.         move.l  dosaddr(a5),a6
  884. *  Lock = Lock(name,accessMode)
  885. *   d0          d1      d2
  886.         CALL    Lock(a6)
  887.         tst.l   d0              ;Q.  Lock obtained?
  888.         bne.s   gcdt020         ;A.  yes - continue
  889.         lea     cmpdate(a5),a0  ;A.  no - point to compare date
  890.         moveq.l #2,d0           ;loop control - set 3 longwords to 0
  891. 1$:     clr.l   (a0)+           ;set datestamp to 0's
  892.         dbra    d0,1$           ;   for 3 long words
  893.         movem.l (a7)+,d2-d4     ;restore registers
  894.         clr.l   d0              ;set good return code
  895.         rts                     ;and return
  896.  
  897. gcdt020:
  898. *---------------------------------------------------------------*
  899. *               Now get File Info for file                      *
  900. *---------------------------------------------------------------*
  901.         move.l  d0,d4           ;save Lock
  902.         move.l  d0,d1           ;lock in d1
  903.         lea     fib(a5),a0      ;point to work fib
  904.         move.l  a0,d2           ;FIB pointer in d2
  905.         move.l  dosaddr(a5),a6
  906. *    success = Examine(lock,FIB)
  907. *      d0               d1   d2
  908.         CALL    Examine(a6)
  909.         move.l  d0,-(a7)        ;save Examine return code on stack
  910. *---------------------------------------------------------------*
  911. *       Free the lock obtained above                            *
  912. *---------------------------------------------------------------*
  913.         move.l  d4,d1           ;lock into d1
  914.         move.l  dosaddr(a5),a6
  915. *   UnLock(lock)
  916. *           d1
  917.         CALL    UnLock(a6)      ;free the lock
  918.  
  919.         move.l  (a7)+,d0        ;restore Examine return code from stack
  920.         tst.l   d0              ;Q.  Success?
  921.         beq     gcdt_err        ;A.  No - examine failed
  922.  
  923.         lea     fib(a5),a0      ;point to fib
  924.         lea     fib_DateStamp(a0),a1    ;point to file's datestamp
  925.         lea     cmpdate(a5),a0  ;point to comparison datestamp
  926.         moveq.l #2,d0           ;loop control - move 3 long words
  927. 1$:     move.l  (a1)+,(a0)+     ;move file's datestamp to compare field
  928.         dbra    d0,1$           ;  move all 3 long words
  929.  
  930.         movem.l (a7)+,d2-d4     ;restore registers
  931.         clr.l   d0              ;good return code
  932.         rts                     ;  return to caller
  933.  
  934. gcdt_err:
  935.         lea     exerm(pc),a0
  936.         move.l  a0,d2           ;Set up and write err msg to console
  937.         move.l  #exerl,d3
  938.         move.l  stdout(a5),d1
  939.         move.l  dosaddr(a5),a6
  940. *   Write(file,data,length)
  941. *          d1   d2    d3
  942.         CALL    Write(a6)
  943.         movem.l (a7)+,d2-d4     ;restore registers
  944.         moveq.l #20,d0          ;set bad return code
  945.         rts                     ;and return
  946.  
  947.         PAGE
  948. *****************************************************************
  949. *     Section Name: copyfile                                    *
  950. *                                                               *
  951. *         Function: Copies input file to output file            *
  952. *                                                               *
  953. *       Entry Data: d0 - file handle for (opened) output file   *
  954. *                   d1 - file handle for (opened) input file    *
  955. *                                                               *
  956. *        Exit Data: d0 - return code (0 = success)              *
  957. *                                                               *
  958. *****************************************************************
  959.  
  960. copyfile:
  961.         movem.l d3-d6/a2-a4,-(a7)       ;save registers
  962.         move.l  d0,d4                   ;save output file handle
  963.         move.l  d1,d5                   ;save input file handle 
  964.         move.l  databuf(a5),d0          ;address of data buffer
  965.         bne.s   cpfl010                 ;bypass alloc if buffer exists
  966. *---------------------------------------------------------------*
  967. *       Allocate work buffer for reading/writing                *
  968. *---------------------------------------------------------------*
  969.         move.l  #RW_BUFS,d0     ;size of buffer
  970.         move.l  #MEMF_CLEAR,d1  ;allocation type
  971.         move.l  Absbase,a6      ;Exec base
  972. *  *ptr = AllocMem(size,type)
  973. *   d0              d0   d1
  974.         CALL    AllocMem(a6)    ;allocate buffer
  975.         move.l  d0,databuf(a5)  ;save and test address
  976.         bne     cpfl010         ;continue if alloc successful
  977. *---------------------------------------------------------------*
  978. *       Unable to allocate buffer - gotta quit                  *
  979. *---------------------------------------------------------------*
  980.         move.l  stdout(a5),d1           ;Std Output file handle
  981.         lea     nomem(pc),a0
  982.         move.l  a0,d2           ;address message
  983.         move.l  #nomeml,d3      ;length of it.
  984.         move.l  dosaddr(a5),a6          ;DOSBase into a6
  985. *   Write(file,data,length)
  986. *          d1   d2    d3
  987.         CALL    Write(a6)       ;Send message to standard out
  988.         bra     cpfl_err        ;and leave
  989.  
  990. cpfl010:
  991. *---------------------------------------------------------------*
  992. *               Read input file                                 *
  993. *---------------------------------------------------------------*
  994.         move.l  d5,d1           ;input file handle
  995.         move.l  databuf(a5),d2  ;address of buffer
  996.         move.l  #RW_BUFS,d3     ;max length to read
  997.         move.l  dosaddr(a5),a6
  998. *  actualLength = Read(file,buffer,maxLength)
  999. *      d0               d1   d2      d3
  1000.         CALL    Read(a6)
  1001.         move.l  d0,d6           ;save actual length read
  1002.         beq     cpfl090         ;0 ==> end-of-file
  1003.         bpl.s   cpfl020         ; > 0 data read OK
  1004. *---------------------------------------------------------------*
  1005. *       A Read error has occured                                *
  1006. *---------------------------------------------------------------*
  1007.         move.l  dosaddr(a5),a6
  1008. *  error = IoErr()
  1009. *    d0
  1010.         CALL    IoErr(a6)       ;get actual error value
  1011.         move.l  d0,work(a5)     ;store in parm list for Printf
  1012.         lea     rderrm(pc),a0   ;string pattern
  1013.         lea     work(a5),a1     ;arg array
  1014.         move.l  arpbase(a5),a6
  1015. *  count = Printf(*string,*arg-array)
  1016. *   d0               a0      a1
  1017.         CALL    Printf(a6)      ;write error message
  1018.         bra.s   cpfl_err        ;take error exit
  1019.  
  1020. cpfl020:
  1021. *---------------------------------------------------------------*
  1022. *       Write same data to output file                          *
  1023. *---------------------------------------------------------------*
  1024.         move.l  d4,d1           ;output file handle
  1025.         move.l  databuf(a5),d2  ;buffer address
  1026.         move.l  d6,d3           ;length of data read
  1027.         move.l  dosaddr(a5),a6
  1028. *  returnedLength = Write(file,buffer,length);
  1029. *      d0                  d1   d2      d3
  1030.         CALL    Write(a6)       ;write data to output file
  1031.         cmp.l   d0,d6           ;Q. did we write all the data?
  1032.         beq.s   cpfl010         ;A. YES - loop on for rest of data
  1033.  
  1034. *---------------------------------------------------------------*
  1035. *   An error occurred writing, since not all data was written   *
  1036. *---------------------------------------------------------------*
  1037.         move.l  dosaddr(a5),a6
  1038. *  error = IoErr()
  1039. *    d0
  1040.         CALL    IoErr(a6)       ;get actual error value
  1041.         move.l  d0,work(a5)     ;store in parm list for Printf
  1042.         lea     wrerrm(pc),a0   ;string pattern
  1043.         lea     work(a5),a1     ;arg array
  1044.         move.l  arpbase(a5),a6
  1045. *  count = Printf(*string,*arg-array)
  1046. *    d0             a0       a1
  1047.         CALL    Printf(a6)      ;write error message
  1048.  
  1049. cpfl_err:
  1050.         movem.l (a7)+,d3-d6/a2-a4       ;restore registers
  1051.         moveq.l #20,d0          ;error return code
  1052.         rts                     ;return to caller
  1053.  
  1054. cpfl090:
  1055.         movem.l (a7)+,d3-d6/a2-a4       ;restore registers
  1056.         clr.l   d0              ;good return code
  1057.         rts                     ;return
  1058.  
  1059.         PAGE
  1060. *****************************************************************
  1061. *     Section Name: getfib                                      *
  1062. *                                                               *
  1063. *         Function: Gets the FileInfoBlock for the passed       *
  1064. *                   named file                                  *
  1065. *                                                               *
  1066. *       Entry Data: a5 - Address of global work area            *
  1067. *                   a0 - address of file name string            *
  1068. *                                                               *
  1069. *        Exit Data: d0 - return code (0 = success)              *
  1070. *                   fib(a5) - filled in File Info block         *
  1071. *                                                               *
  1072. *****************************************************************
  1073.  
  1074. getfib:
  1075.         movem.l d2/d3,-(a7) ;save registers
  1076. *---------------------------------------------------------------*
  1077. *         Get a shared lock on the file                         *
  1078. *---------------------------------------------------------------*
  1079.         move.l  a0,d1           ;file name in d1
  1080.         move.l  #ACCESS_READ,d2 ;lock type
  1081.         move.l  dosaddr(a5),a6  ;DOSBase
  1082. *  lock = Lock(name,mode)
  1083. *   d0          d1   d2
  1084.         CALL    Lock(a6)
  1085.         tst.l   d0              ;Q.  Lock obtained?
  1086.         beq.s   gfib_err        ;A.  No - return error
  1087.  
  1088.         move.l  d0,d3           ;save lock
  1089. *---------------------------------------------------------------*
  1090. *               now get File Info from lock                     *
  1091. *---------------------------------------------------------------*
  1092.         move.l  d3,d1           ;lock in d1
  1093.         lea     fib(a5),a0      ;address fib
  1094.         move.l  a0,d2           ;FIB address in d2
  1095.         move.l  dosaddr(a5),a6
  1096. *  boolean = Examine(lock,&FileInfoBlock);
  1097. *    d0               d1       d2
  1098.         CALL    Examine(a6)
  1099.         move.l  d0,-(a7)        ;save Examine return code
  1100. *---------------------------------------------------------------*
  1101. *       Free Lock (we are done with it)                         *
  1102. *---------------------------------------------------------------*
  1103.         move.l  d3,d1           ;lock in d1
  1104.         move.l  dosaddr(a5),a6
  1105. *  UnLock(lock);
  1106. *          d1
  1107.         CALL    UnLock(a6)      ;free lock
  1108.  
  1109.         move.l  (a7)+,d0        ;restore return code from examine
  1110.         tst.l   d0              ;Q.  Good return from Examine?
  1111.         beq.s   gfib_err        ;A.  no - take error exit
  1112.  
  1113. *---------------------------------------------------------------*
  1114. *               Successful processing                           *
  1115. *---------------------------------------------------------------*
  1116.         clr.l   d0              ;set good return code
  1117.         movem.l (a7)+,d2/d3     ;restore registers
  1118.         rts                     ;and return
  1119.  
  1120. *---------------------------------------------------------------*
  1121. *               Error exit                                      *
  1122. *---------------------------------------------------------------*
  1123. gfib_err:
  1124.         moveq.l #20,d0          ;set bad return code
  1125.         movem.l (a7)+,d2/d3     ;restore registers
  1126.         rts                     ;and return
  1127.  
  1128.         PAGE
  1129. *****************************************************************
  1130. *     Section Name: setdate                                     *
  1131. *                                                               *
  1132. *         Function: Sets the datestamp for the output file      *
  1133. *                   to match that contained in the input FIB    *
  1134. *                                                               *
  1135. *       Entry Data: outbuf(a5) contains full path name of       *
  1136. *                       output file                             *
  1137. *                   a0 - the address of the input file's FIB    *
  1138. *                                                               *
  1139. *        Exit Data: N/A (Note: errors are considered non-       *
  1140. *                   critical and are ignored)                   *
  1141. *****************************************************************
  1142.  
  1143. setdate:
  1144.         movem.l d3/d4/a3/a4,-(a7)       ;save registers
  1145.         move.l  a0,a3           ;save address of fib
  1146. *---------------------------------------------------------------*
  1147. *       Get Handler Process address                             *
  1148. *---------------------------------------------------------------*
  1149.         lea     outbuf(a5),a0   ;get output file name
  1150.         move.l  a0,d1
  1151.         move.l  dosaddr(a5),a6
  1152. *  process - DeviceProc(name)
  1153. *     d0                 d1
  1154.         CALL    DeviceProc(a6)
  1155.         tst.l   d0              ;Q. Handler found?
  1156.         beq.s   sdat090         ;A.  no - can't continue
  1157.         move.l  d0,a4           ;    yes - save handler address
  1158.  
  1159. *---------------------------------------------------------------*
  1160. *       Get a lock on the output file                           *
  1161. *---------------------------------------------------------------*
  1162.         lea     outbuf(a5),a0   ;name of output file
  1163.         move.l  a0,d1
  1164.         move.l  #ACCESS_READ,d2 ;lock type (shared)
  1165.         move.l  dosaddr(a5),a6
  1166. *  lock = Lock(name,accessMode)
  1167. *   d0          d1     d2
  1168.         CALL    Lock(a6)
  1169.         tst.l   d0              ;Q. Lock obtained?
  1170.         beq.s   sdat090         ;A. No - cannot continue
  1171.         move.l  d0,-(a7)        ;   yes - save lock on stack
  1172. *---------------------------------------------------------------*
  1173. *               Get lock for parent directory                   *
  1174. *---------------------------------------------------------------*
  1175.         move.l  d0,d1           ;lock into d1
  1176. *  lock = ParentDir(lock)
  1177. *   d0               d1
  1178.         CALL    ParentDir(a6)
  1179.         move.l  d0,d3           ;save lock (note: this CAN be zero)
  1180. *---------------------------------------------------------------*
  1181. *  Free the first lock we obtained - don't need it any more     *
  1182. *---------------------------------------------------------------*
  1183.         move.l  (a7)+,d1        ;lock for output file
  1184. *  UnLock(lock)
  1185. *          d1
  1186.         CALL    UnLock(a6)      ;free this lock
  1187. *---------------------------------------------------------------*
  1188. *  Now build the file name as a BCPL string                     *
  1189. *       NOTE: this name MUST NOT include any path information,  *
  1190. *             just the file name                                *
  1191. *---------------------------------------------------------------*
  1192.         lea     strwork+1(a5),a0        ;string work area (saving the 1st byte)
  1193.         lea     fib_FileName(a3),a1     ;file name in passed FIB
  1194.         clr.l   d0                      ;set count to 0
  1195. 1$:     addq.b  #1,d0           ;increment count
  1196.         move.b  (a1)+,(a0)+     ;move byte
  1197.         bne.s   1$              ;loop until null byte
  1198.         subq.b  #1,d0           ;don't count null byte
  1199.         move.b  d0,strwork(a5)  ;length into first byte
  1200. *---------------------------------------------------------------*
  1201. *       Build Argument list for DOS Packet                      *
  1202. *---------------------------------------------------------------*
  1203.         clr.l   pktarg0(a5)     ;first argument null
  1204.         move.l  d3,pktarg1(a5)  ;second argument is lock of parent dir
  1205.         lea     strwork(a5),a0  ;pointer to BSTR file name
  1206.         move.l  a0,d0
  1207.         lsr.l   #2,d0           ;convert to BCPL pointer (BPTR)
  1208.         move.l  d0,pktarg2(a5)  ;third argument is BSTR pointer to file name
  1209.         lea     fib_DateStamp(a3),a0
  1210.         move.l  a0,pktarg3(a5)  ;fourth arg is REAL pointer to DateStamp
  1211. *---------------------------------------------------------------*
  1212. *   Now use the ARP routine to send the DOS Packet              *
  1213. *---------------------------------------------------------------*
  1214.         move.l  #ACTION_SET_DATE,d0
  1215.         lea     pktarg0(a5),a0
  1216.         move.l  a4,a1           ;handler process
  1217.         move.l  arpbase(a5),a6
  1218. *  Result1 = SendPacket(action, args, handler)
  1219. *    d0                   d0     a0     a1
  1220.         CALL    SendPacket(a6)
  1221. *---------------------------------------------------------------*
  1222. * ignore return code - if it worked, it worked - if not, not    *
  1223. *                                                               *
  1224. *       Free the lock on the Parent Directory                   *
  1225. *---------------------------------------------------------------*
  1226.         move.l  d3,d1
  1227.         move.l  dosaddr(a5),a6
  1228. *  UnLock(lock)
  1229. *          d1
  1230.         CALL    UnLock(a6)
  1231.  
  1232. sdat090:
  1233.         movem.l (a7)+,d3/d4/a3/a4       ;restore registers
  1234.         rts
  1235.  
  1236.         PAGE
  1237. *---------------------------------------------------------------*
  1238. *                    Program Constants                          *
  1239. *---------------------------------------------------------------*
  1240.  
  1241. dosname dc.b    'dos.library',0
  1242. arpname dc.b    'arp.library',0
  1243.  
  1244.         CNOP    0,4
  1245. nomem   dc.b    'Unable to allocate work area - aborted',$0a
  1246. nomeml  EQU     *-nomem
  1247.  
  1248. noarp   dc.b    'Unable to Open ARP Library - aborted',$0a
  1249. noarpl  EQU     *-noarp
  1250.  
  1251. nosinm  dc.b    'Unable to locate SINCE file - aborted',$0a
  1252. nosinml EQU     *-nosinm
  1253.  
  1254. noout   dc.b    'Unable to locate TO directory - aborted',$0a
  1255. nooutl  EQU     *-noout
  1256.  
  1257. notdir  dc.b    'Specified TO parameter is not a directory - aborted',$0a
  1258. notdirl EQU     *-notdir
  1259.  
  1260. templ   dc.b    'FROM/A,,,,,,,,,,,,TO/A/K,SINCE/K',0
  1261.  
  1262. cmdpr   dc.b    'Usage:  ',$9b,'1;32mUpdate',$9b,'0;31m [FROM] ',$9b,'1;32mobj1 '
  1263.         dc.b    $9b,'0;31m[obj2 ... obj12] ',$9b,'1;32mTO dir',$9b
  1264.         dc.b    '0;31m [SINCE mfile]',$0a,$0a
  1265.         dc.b    '   Where ',$9b,'1mobj1...obj12',$9b,'0m are either files '
  1266.         dc.b    'or directories (with or without',$0a
  1267.         dc.b    '             wildcards, specifying input files to be checked'
  1268.         dc.b    $0a,$0a
  1269.         dc.b    '         ',$9b,'1mdir',$9b,'0m is the output directory '
  1270.         dc.b    'to receive the qualifying files',$0a,$0a
  1271.         dc.b    '    and  ',$9b,'1mmfile',$9b,'0m specifies the '
  1272.         dc.b    'optional file whose datestamp will be ',$0a
  1273.         dc.b    '             used to determine which input files '
  1274.         dc.b    'will updated in the ',$0a
  1275.         dc.b    '             output directory - NOTE that if no SINCE '
  1276.         dc.b    'file is specified,',$0a
  1277.         dc.b    '             the corresponding file in the TO directory '
  1278.         dc.b    'will be checked',$0a,0
  1279.  
  1280. ferrm   dc.b    'Command format error',$0a
  1281. ferrml  EQU     *-ferrm
  1282.  
  1283. fline   dc.b    '... %s ',0
  1284. foklin  dc.b    '  copied',$0a
  1285. foklinl EQU     *-foklin
  1286. iopnerm dc.b    '  Unable to Open Input file - Aborted',$0a
  1287. iopnerl EQU     *-iopnerm
  1288. oopnerm dc.b    '  Unable to Open Output file - Aborted',$0a
  1289. oopnerl EQU     *-oopnerm
  1290. exerm   dc.b    '  Error examining output file after locking - Aborted',$0a
  1291. exerl   EQU     *-exerm
  1292. rderrm  dc.b    ' Read Error - code %ld',$0a,0
  1293. wrerrm  dc.b    ' Write Error - code %ld',$0a,0
  1294. dlokerr dc.b    '  Unable to Lock Input directory %s - Aborted',$0a,0
  1295. dexerr  dc.b    '  Unable to Examine Input directory %s - Aborted',$0a,0
  1296. baddir  dc.b    '  Corrupted Directory chain - error %ld - Aborted',$0a,0
  1297.  
  1298.         CNOP    0,4
  1299.         PAGE
  1300. *---------------------------------------------------------------*
  1301. *                          Work Area                            *
  1302. * Note: the following areas are actually obtained by an Alloc-  *
  1303. *       Mem system call, and addressed relative to register a5  *
  1304. *---------------------------------------------------------------*
  1305.         OFFSET  0
  1306. cmdline ds.l    1               ;pointer to command line
  1307. cmdlen  ds.l    1               ;length of command line
  1308. dosaddr ds.l    1               ;address of DOSBase
  1309. arpbase ds.l    1               ;address of ArpBase
  1310. stdout  ds.l    1               ;file handle of std output
  1311. databuf ds.l    1               ;pointer to 16K data buffer for copying files
  1312. argv    ds.l    12              ;argument vectors for input names (FROM)
  1313. todir   ds.l    1               ;arg vector for TO keyword
  1314. sinfil  ds.l    1               ;arg vector for SINCE file
  1315. cmpdate ds.l    3               ;DateStamp for compare
  1316. work    ds.l    1               ;work word (for printf)
  1317. outfnam ds.l    1               ;pointer into outbuf for file name
  1318. pktargs ds.l    7               ;arg array for DOS Packets
  1319. pktarg0 EQU     pktargs
  1320. pktarg1 EQU     pktargs+4
  1321. pktarg2 EQU     pktargs+8
  1322. pktarg3 EQU     pktargs+12
  1323. argc    ds.w    1               ;argument count (max 64)
  1324.  
  1325.         CNOP    0,4
  1326. fib     ds.b    fib_SIZEOF      ;work FileInfoBlock
  1327.         CNOP    0,4
  1328. anchor  ds.b    AP_SIZEOF       ;arp w/c file search anchor
  1329. fname   ds.b    128             ;buffer for arp to build file name
  1330.         CNOP    0,4
  1331. outbuf  ds.b    128             ;buffer for output file path name
  1332. dirbuf  ds.b    128
  1333.  
  1334. strwork ds.b    128             ;buffer for BSTR conversion
  1335. wk_lgth equ     *
  1336.  
  1337.         END
  1338.